/*
 * Javlov - a Java toolkit for reinforcement learning with multi-agent support.
 * 
 * Copyright (c) 2009 Matthijs Snel
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.javlov.world.grid;
/**
 * Sets the directions, used mainly on the grid, and creates the possibility for
 * finding the opposite direction.
 * 
 * @author University of Utrecht
 */
public class Direction {
    final static  int NORTH;
    final static  int NORTHEAST;
    final static  int EAST;
    final static  int SOUTHEAST;
    final static  int SOUTH;
    final static  int SOUTHWEST;
    final static  int WEST;
    final static  int NORTHWEST;

    final static Direction north;
    final static Direction northeast;
    final static Direction east;
    final static Direction south;
    final static Direction southeast;
    final static Direction southwest;
    final static Direction west;
    final static Direction northwest;
    
    final static Direction all[], all2D[][];

    static{ 
      NORTH = 0;
      NORTHEAST = 1;
      EAST = 2;
      SOUTHEAST = 3;
      SOUTH = 4;
      SOUTHWEST = 5;
      WEST = 6;
      NORTHWEST = 7;

      all2D = new Direction[3][3];
      
      //in the following, add 1 to the directions because array can't have negative index
      north     = new Direction(NORTH, 0, -1);
      all2D[0+1][-1+1] = north;
      northeast = new Direction(NORTHEAST, 1, -1);
      all2D[1+1][-1+1] = northeast;
      east      = new Direction(EAST, 1, 0);
      all2D[1+1][0+1] = east;
      southeast = new Direction(SOUTHEAST, 1, 1);
      all2D[1+1][1+1] = southeast;
      south     = new Direction(SOUTH, 0, 1);
      all2D[0+1][1+1] = south;
      southwest = new Direction(SOUTHWEST, -1, 1);
      all2D[-1+1][1+1] = southwest;
      west      = new Direction(WEST, -1, 0);
      all2D[-1+1][0+1] = west;
      northwest = new Direction(NORTHWEST, -1, -1);
      all2D[-1+1][-1+1] = northwest;

      all = new Direction[8];

      all[NORTH]     = north;
      all[NORTHEAST] = northeast;
      all[EAST]      = east;
      all[SOUTHEAST] = southeast;
      all[SOUTH]     = south;
      all[SOUTHWEST] = southwest;
      all[WEST]      = west;
      all[NORTHWEST] = northwest;
    }
    
    public static Direction get(int x, int y) {
    	return all2D[x+1][y+1];
    }
  
  /**
   * Returns the opposite direction from the one given as a parameter,
   * when the int given does not represent a valid direction a default
   * negative number is returned.
   */
  public static int opposite(int direction)
    {
	if(direction == NORTH)
	    return SOUTH;
	else if(direction == SOUTH)
	    return NORTH;
	else if(direction == NORTHWEST)
	    return SOUTHEAST;
	else if(direction == SOUTHEAST)
	    return NORTHWEST;
	else if(direction == NORTHEAST)
	    return SOUTHWEST;
	else if(direction == SOUTHWEST)
	    return NORTHEAST;
	else if(direction == WEST)
	    return EAST;
	else if(direction == EAST)
	    return WEST;
	else
	    return -1;
    }

    private int _direction;
    private int _x;
    private int _y;

    public Direction(int direction, int x, int y)
    {
	_direction = direction;
	_x = x;
	_y = y;
    }

    /**
     * "Goes" into a specific direction using the GridCell passed to it as
     * starting point, by returning the GridCell that neighbours the starting
     * point in the direction of this Direction.
     * 
     * @param cell the starting point
     * @return the GridCell neighbouring the starting point in this Direction
     */
    public GridCell go(GridCell cell)
    {
	return cell.getNeighbour(_direction);
    }

    public Direction opposite()
    {
	return all[Direction.opposite(_direction)];
    }

    public Direction next()
    {
	return all[(_direction + 1) % 8];
    }

    public int x()
    {
	return _x;
    }

    public int y()
    {
	return _y;
    }
}


